package com.zhixiang.xaec.service.system.impl;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Date;

import javax.annotation.Resource;

import net.sf.json.JSONArray;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;

import org.aspectj.lang.JoinPoint;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Comment;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import com.zhixiang.core.dao.BaseDao;
import com.zhixiang.core.service.impl.BaseServiceImpl;
import com.zhixiang.core.util.AppUtil;
import com.zhixiang.core.util.Utils;
import com.zhixiang.xaec.dao.system.SystemLogDao;
import com.zhixiang.xaec.entity.system.SystemLog;
import com.zhixiang.xaec.service.system.SystemLogService;
@Service("systemLogService")
public class SystemLogServiceImpl extends BaseServiceImpl<SystemLog, Long> implements SystemLogService
{   
    //取项目里的hibernateTemplate，会出现两个对象拥有同一个ID的冲突
    //HibernateTemplate hibernateTemplate=(HibernateTemplate)AppUtil.getBean("hibernateTemplate");
    //自己重新open一个session
    SessionFactory sessionFactory=(SessionFactory)AppUtil.getBean("sessionFactory");
    @Override
    public String delete(String[] ids)
    {
        for(String id:ids){
            SystemLog s=new SystemLog();
            s.setId(Long.parseLong(id));
            sessionFactory.getCurrentSession().delete(s);
        }
         return null;
    }
    @Override
    @Resource(type = SystemLogDao.class)
    public void setBaseDao(BaseDao<SystemLog, Long> dao)
    {
        setDao(dao);
    }
    
    //获取当前登录用户名,便于构建日志对象使用
    public String receiveUserName(){
        if(SecurityContextHolder.getContext() == null){  
            return null;  
        }  
          
        if(SecurityContextHolder.getContext().getAuthentication() == null){  
            return null;  
        }  
          
        UserDetails userDetails = (UserDetails) SecurityContextHolder  
                .getContext().getAuthentication().getPrincipal();  
          
        if(userDetails == null){  
            return null;  
        }  
        
        String userName = userDetails.getUsername();  
        
        if(userName == null || userName.equals("")){  
            return null;  
        } 
        
        return userName;
        
    }
    /** 
     * 使用Java反射来获取被拦截方法(insert、update)的参数值， 
     * 获取操作内容 
     * 
     */  
    public String operationDetail(Object[] args){  
  
        if (args == null) {  
            return null;  
        }  
        
      //  String json=null;
      /*   方法1：最原始的，用反射机制，自己拼“属性：值 ”
       *   这种方式不会出现死循环,但效率低下
        StringBuffer rs = new StringBuffer();
        rs.append("[");
        // 遍历参数对象  
        for (Object info : args) {  
           object2String(info,rs);  
        }  
          rs.append("]");
        return rs.toString();  */
        //方法2：GSON中的方法，但是转json字符串时实体类要使用到@Expose注解
        //去掉@Expose注解，则可防止死循环
//        return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(args);
//        return new Gson().toJson(args);
        //方法3：Jsonplugin  用jsonConfig配置策略来防止死循环  
        //因为本项目STRUTS和前台交互时使用Jsonplugin，因此为了统一期间，此处也使用Jsonplugin
        JsonConfig jsonConfig = new JsonConfig();
        jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);//解决转json的死循环问题策略
        JSONArray jsonArray = JSONArray.fromObject(args,jsonConfig);
        if(jsonArray.toString().length()>1000){
            return jsonArray.toString().substring(0, 1000);
        }
        return jsonArray.toString();
        
        //方法4，@JsonBackReference在实体属性上防止死循环，尤其是一对多关系
        //@JsonIgnoreProperties可以加在类上，注明哪些属性不转JSON字符串
//        ObjectMapper objectMapper =new ObjectMapper();  
//   
//            try
//            {
//                 json=objectMapper.writeValueAsString(args);
//            }
//            catch (JsonProcessingException e)
//            {
//                e.printStackTrace();
//            }//将对象转成json
//            
//            return json;

    }
    /**
     * 保存日志
     * 
     */
    @Override
    public void insertLog(JoinPoint joinPoint,String opration,Object beforeModif)
    {
        
        //获取登录管理员id  
        String userName = receiveUserName();  
          
        if(userName == null){//没有管理员登录  
            return;  
        }           
        //获取操作内容  
        String operationDetail="";
        Comment comment;
        if(beforeModif!=null){
            comment = beforeModif.getClass().getAnnotation(Comment.class);
            operationDetail=operationDetail(new Object[]{beforeModif});
        }else{
            comment = (joinPoint.getArgs())[0].getClass().getAnnotation(Comment.class);
            operationDetail = operationDetail(joinPoint.getArgs());
        }
        //创建日志对象  
        SystemLog log = new SystemLog();  
        log.setUserId(userName);//记录登录账号，log中的username字段用来保存用户的真正名字 
        log.setEntityName(comment == null ? "" : comment.value());
        log.setOperationTime(new Date());//操作时间  
        log.setOperationDetail(operationDetail);//操作内容  
        log.setOperation(opration);//操作           
        sessionFactory.getCurrentSession().save(log);//添加日志  
        
    }  
    /**
     * 判断是添加还是修改
     * 仅适用单主键
     * 
     */
    @Override
    public String judgeOpration(JoinPoint joinPoint)
    {   
           String opration="";    
//           获取实体类中ID的名字
           ClassMetadata meta = 
           sessionFactory.getClassMetadata((joinPoint.getArgs())[0].getClass());//仅适用有一个@ID的实体类
           String idName=meta.getIdentifierPropertyName();          
           Object sid=null;
        try
        {
            sid = Utils.invokeMethod((joinPoint.getArgs())[0],Utils.field2GetMethod(idName),null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
           if(sid==null){
               opration= "添加";
           }else{
               if(sessionFactory.openSession().get((joinPoint.getArgs())[0].getClass(), (Serializable)sid)==null){
                   opration= "添加";
               }else{
                   opration= "修改";
               }
           }
           return opration;  
    }
    /**
     * 如果是修改，调用此方法保存修改前的内容
     */
    @Override
    public Object befoModifOrDele(JoinPoint joinPoint)
    {      
        //通过joinPoint获取被操作目标对象的类型，再获取父类的泛型，就是实体的类型
        Class<?> targetClass = joinPoint.getTarget().getClass();
        Class<?> entityClass = (Class<?>)((ParameterizedType)targetClass.getGenericSuperclass()).getActualTypeArguments()[0];
        Object obj=null;
        try
        {
            //修改因为传过来是对象，所以要通过反射去取id的值
            ClassMetadata meta = sessionFactory.getClassMetadata(entityClass);//仅适用有一个@ID的实体类
            String idName=meta.getIdentifierPropertyName();          
            Object sid = Utils.invokeMethod((joinPoint.getArgs())[0],Utils.field2GetMethod(idName),null);
            obj=sessionFactory.openSession().get(entityClass, (Serializable)sid);
        }
        catch (Exception e)
        {
            //删除传过来的直接就是ID
            try
            {               
                obj=sessionFactory.getCurrentSession().get(entityClass, (Serializable)(joinPoint.getArgs())[0]);
            }
            catch (Exception e1)
            {
            }
        }
    return obj;
        
    }
     
    /**
     * 将对象转化成 属性名：值的方式的字符串
     */
    public String object2String(Object obj,StringBuffer str){
        
        // 获取对象的所有方法  
        Method[] methods = obj.getClass().getDeclaredMethods();  
          
        // 遍历方法，判断get方法  
        for (Method method : methods) {  
              
            String methodName = method.getName();  
            // 判断是不是get方法  
            if (methodName.indexOf("get") == -1) {// 不是get方法  
                continue;// 不处理  
            }  
              
            Object rsValue = null;  
            try {  
                  
                // 调用get方法，获取返回值  
                rsValue = method.invoke(obj);  
                  
                if (rsValue == null) {//没有返回值  
                    continue;  
                }  
                  
            } catch (Exception e) {  
                continue;  
            }  
              
            //将值加入内容中  
            str.append("(" + methodName.substring(3) + " : " + rsValue + ")");  
        }   
        return str.toString();   
    }
    
}  

